#!/bin/bash -e
#   * compile instructions: put this file in
#   *         `steamapps/common/Dyson Sphere Program/CustomMod`
#   * folder, open a terminal in the same folder, and execute:
#   *
#   * ```
#   *     chmod +x ${file}.cs
#   *     ./${file}.cs
#   * ```
#   *
#   * then the mod will be compiled automatically.
#   *
#   * Here we wrote a shebang like file, which is correct
#   * in my computer (Manjaro XFCE), if such script do not work
#   * in your computer, you could just try the instructions below :

if [ -z "$__DOTNET_CSC" ]; then
    export __DOTNET_CSC="`find /usr/share/dotnet -type f -name dotnet` `find /usr/share/dotnet -name csc.dll`"
    echo '$'"__DOTNET_CSC not set yet, you should execute"
    echo "export __DOTNET_CSC='$__DOTNET_CSC'"
    echo "manually, or this alert will occur each time you execute this script."
fi

__MODE_VERBOSE=81 # is the line number of "#define VERBOSE", may be modified
__MODE_DEBUG__=$((__MODE_VERBOSE+1))
__MODE_RELEASE=$((__MODE_DEBUG__+1))

case $1 in
    V)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    v)       _MODE__SELECT_=$__MODE_VERBOSE     ;;
    VERBOSE) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    verbose) _MODE__SELECT_=$__MODE_VERBOSE     ;;
    D)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    d)       _MODE__SELECT_=$__MODE_DEBUG__     ;;
    DEBUG)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    debug)   _MODE__SELECT_=$__MODE_DEBUG__     ;;
    *)       _MODE__SELECT_=$__MODE_RELEASE     ;;
esac

export GAME_NAME="${0%\.cs}" # now, file name should be equals to ${GAME_NAME}.cs, the benefit is, we could only change the name, rather than change filename and $GAME_NAME.
export GAME_NAME="The Scroll Of Taiwu Alpha V1.0"
export FILE_NAME="$0"
export ASSEMBLY="Assembly-CSharp"
export GAME_BASE_DIR="../common/The Scroll Of Taiwu"
export PLUGIN_ID="Neutron3529.Taiwu.BetterChangeAtkPart"
export NAMESPACE_ID="Neutron3529.BetterChangeAtkPart"

( yes "" | head -n $_MODE__SELECT_ | head -n-1  ; tail $FILE_NAME -n+$_MODE__SELECT_ ) | sed s/%%NAMESPACE_ID%%/${NAMESPACE_ID}/g | sed s/%%PLUGIN_ID%%/${PLUGIN_ID}/g | $__DOTNET_CSC -nologo -t:library \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/0Harmony.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/core/BepInEx.Harmony.dll" \
  `[ -e "${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll" ] && echo "-r:\"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/netstandard.dll\""` \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/System.Core.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/UnityEngine.CoreModule.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/mscorlib.dll" \
  -r:"${GAME_BASE_DIR}/${GAME_NAME}_Data/Managed/Assembly-CSharp-886238F0C737D5551CA4940C9724A53C94395A280021C721ED03A5241482CB97.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/plugins/YanCore/YanLib.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/plugins/YanCore/UnityUIKit.dll" \
  -r:"${GAME_BASE_DIR}/BepInEx/plugins/YanCore/TaiwuUIKit.dll" \
  -out:"${GAME_BASE_DIR}/BepInEx/plugins/${FILE_NAME%.*}".dll \
  -optimize \
  - && rm -f "${GAME_BASE_DIR}/BepInEx/config/${PLUGIN_ID}.cfg";

if [ -n "$2" ]; then
    git add ${FILE_NAME}
    case $2 in
        R) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        r) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        RANDOM) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        random) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        U) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        u) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        UPLOAD) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        upload) git commit -am "`curl -s http://whatthecommit.com/index.txt`" ;;
        *) git commit -am "$2" ;;
    esac
    git push
fi
exit


#define VERBOSE // the line of __MODE_VERBOSE
#define DEBUG
#define USE_UI


using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;

using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;

#if USE_UI

using TaiwuUIKit.GameObjects;
using UnityUIKit.Core;
using UnityUIKit.GameObjects;
using YanLib.ModHelper;

#endif

namespace %%NAMESPACE_ID%%
{


    public class Settings {
        // Token: 0x06000008 RID: 8 RVA: 0x00003ED4 File Offset: 0x000020D4
        public void Init(ConfigFile config)
        {
            this.atkPart = config.Bind("config", "atkPart", Main.atkPart, "选择各部位概率权重最大的招数来变招，含义分别是"+string.Join(",",Main.natkPart));
            this.atkTyp = config.Bind("config", "atkTyp", Main.atkTyp, "式的变招权重，数组含义依次是"+string.Join(",",Main.natkTyp));
            this.aTF = config.Bind("config", "aTF", Main.aTF, "式的变招系数，权重计算是，((int)(击中概率*100))*概率权重+变招系数*变招权重");
            this.use_ui = config.Bind("config", "use_ui", Main.use_ui, "是否使用UI");
            this.Config = config;
        }

        // Token: 0x06000009 RID: 9 RVA: 0x000040E3 File Offset: 0x000022E3
        public void Save()
        {
            this.Config.Save();
        }

        // Token: 0x04000008 RID: 8
        private ConfigFile Config;

        // Token: 0x04000009 RID: 9
        public ConfigEntry<int[]> atkPart;
        public ConfigEntry<int[]> atkTyp;
        public ConfigEntry<int> aTF;
        public ConfigEntry<bool> use_ui;
    }
#if USE_UI
    public class UI {
        public static ModHelper Mod;
        public static List<Sub> subs=new List<Sub>();
        List<Action> refresh_list=new List<Action>();

        public class Sub {
            public TaiwuLabel lab;
            public TaiwuInputField taiwuInputField;
            public int[] arr;
            public int idx;
            public string what;
            public Sub(int[] _arr,int _idx,string _what){
                arr=_arr;
                idx=_idx;
                what=_what;
                taiwuInputField = new TaiwuInputField();
                taiwuInputField.Name = what;
                taiwuInputField.Text = arr[idx].ToString();
                lab = new TaiwuLabel { Name = "Label", Text = what };
                taiwuInputField.OnEndEdit = delegate(string value, InputField inputField) {
                    this.arr[this.idx]=int.Parse(value);
                    Main.settings.atkPart.Value=Main.atkPart;
                    Main.settings.atkTyp.Value=Main.atkTyp;
                };
            }
            public Action Addto(Container container){
                container.Children.Add(this.lab);
                container.Children.Add(this.taiwuInputField);
                return delegate(){
                    this.taiwuInputField.Text = this.arr[this.idx].ToString();
                };
            }
        }
        public void Init() {
            Mod = new ModHelper("%%PLUGIN_ID%%", "%%NAMESPACE_ID%%");
            Container container = new Container();
            container.Name = "%%PLUGIN_ID%%";
            container.Group.Spacing = 5f;
            container.Group.Direction = (Direction)1;
            container.Element.PreferredSize.Add(0f);
            container.Element.PreferredSize.Add(420f);

            Container container2 = new Container();
            container2.Name = "%%NAMESPACE_ID%%";
            container2.Element.PreferredSize.Add(0f);
            container2.Element.PreferredSize.Add(60f);
            container2.Group.Direction = 0;
            container2.Group.Spacing = 4f;
            container2.Children.Add(new TaiwuLabel { Name = "Label", Text = "部位概率权重，“不变”一项的击中概率默认为1%" });
            container.Children.Add(container2);
            container2 = new Container();
            container2.Element.PreferredSize.Add(0f);
            container2.Element.PreferredSize.Add(60f);
            container2.Group.Direction = 0;
            container2.Group.Spacing = 4f;
            container.Children.Add(container2);
            for(int i=0;i<8;i++){
                refresh_list.Add((new Sub(Main.atkPart,i,Main.natkPart[i])).Addto(container2));
                if ((i&3)==3){
                    container.Children.Add(container2);
                    container2 = new Container();
                    container2.Element.PreferredSize.Add(0f);
                    container2.Element.PreferredSize.Add(60f);
                    container2.Group.Direction = 0;
                    container2.Group.Spacing = 4f;
                }
            }
            {
                TaiwuToggle taiwuToggle = new TaiwuToggle();
                taiwuToggle.Text = "追求命中率";
                taiwuToggle.isOn = false;
                taiwuToggle.TipTitle = "功能说明";
                taiwuToggle.TipContant = "修改前7项参数系数到100，不会改变招式获取设置";
                taiwuToggle.onValueChanged = delegate(bool value, Toggle tg)
                {
                    Main.atkPart[0]=100;
                    Main.atkPart[1]=100;
                    Main.atkPart[2]=100;
                    Main.atkPart[3]=100;
                    Main.atkPart[4]=100;
                    Main.atkPart[5]=100;
                    Main.atkPart[6]=100;
                    Main.settings.atkPart.Value=Main.atkPart;
                    tg.isOn = false;foreach(var del in refresh_list)del();
                };
                container2.Children.Add(taiwuToggle);
            }
            {
                TaiwuToggle taiwuToggle = new TaiwuToggle();
                taiwuToggle.Text = "打胸背(爆寒毒)";
                taiwuToggle.isOn = false;
                taiwuToggle.TipTitle = "功能说明";
                taiwuToggle.TipContant = "修改前7项参数系数到100，不会改变招式获取设置";
                taiwuToggle.onValueChanged = delegate(bool value, Toggle tg)
                {
                    Main.atkPart[0]=10000;
                    Main.atkPart[1]=100;
                    Main.atkPart[2]=100;
                    Main.atkPart[3]=100;
                    Main.atkPart[4]=100;
                    Main.atkPart[5]=100;
                    Main.atkPart[6]=100;
                    Main.settings.atkPart.Value=Main.atkPart;
                    tg.isOn = false;foreach(var del in refresh_list)del();
                };
                container2.Children.Add(taiwuToggle);
            }
            {
                TaiwuToggle taiwuToggle = new TaiwuToggle();
                taiwuToggle.Text = "打腰腹(爆赤毒)";
                taiwuToggle.isOn = false;
                taiwuToggle.TipTitle = "功能说明";
                taiwuToggle.TipContant = "修改前7项参数系数到100，不会改变招式获取设置";
                taiwuToggle.onValueChanged = delegate(bool value, Toggle tg)
                {
                    Main.atkPart[0]=100;
                    Main.atkPart[1]=10000;
                    Main.atkPart[2]=100;
                    Main.atkPart[3]=100;
                    Main.atkPart[4]=100;
                    Main.atkPart[5]=100;
                    Main.atkPart[6]=100;
                    Main.settings.atkPart.Value=Main.atkPart;
                    tg.isOn = false;foreach(var del in refresh_list)del();
                };
                container2.Children.Add(taiwuToggle);
            }
            {
                TaiwuToggle taiwuToggle = new TaiwuToggle();
                taiwuToggle.Text = "打头(可去势)";
                taiwuToggle.isOn = false;
                taiwuToggle.TipTitle = "功能说明";
                taiwuToggle.TipContant = "修改前7项参数系数到100，不会改变招式获取设置";
                taiwuToggle.onValueChanged = delegate(bool value, Toggle tg)
                {
                    Main.atkPart[0]=100;
                    Main.atkPart[1]=100;
                    Main.atkPart[2]=10000;
                    Main.atkPart[3]=100;
                    Main.atkPart[4]=100;
                    Main.atkPart[5]=100;
                    Main.atkPart[6]=100;
                    Main.settings.atkPart.Value=Main.atkPart;
                    tg.isOn = false;foreach(var del in refresh_list)del();
                };
                container2.Children.Add(taiwuToggle);
            }
            {
                TaiwuToggle taiwuToggle = new TaiwuToggle();
                taiwuToggle.Text = "打手(接招用)";
                taiwuToggle.isOn = false;
                taiwuToggle.TipTitle = "功能说明";
                taiwuToggle.TipContant = "修改前7项参数系数到100，不会改变招式获取设置";
                taiwuToggle.onValueChanged = delegate(bool value, Toggle tg)
                {
                    Main.atkPart[0]=100;
                    Main.atkPart[1]=100;
                    Main.atkPart[2]=100;
                    Main.atkPart[3]=10000;
                    Main.atkPart[4]=10000;
                    Main.atkPart[5]=100;
                    Main.atkPart[6]=100;
                    Main.settings.atkPart.Value=Main.atkPart;
                    tg.isOn = false;foreach(var del in refresh_list)del();
                };
                container2.Children.Add(taiwuToggle);
            }
            {
                TaiwuToggle taiwuToggle = new TaiwuToggle();
                taiwuToggle.Text = "打腿(风筝用)";
                taiwuToggle.isOn = false;
                taiwuToggle.TipTitle = "功能说明";
                taiwuToggle.TipContant = "修改前7项参数系数到100，不会改变招式获取设置";
                taiwuToggle.onValueChanged = delegate(bool value, Toggle tg)
                {
                    Main.atkPart[0]=100;
                    Main.atkPart[1]=100;
                    Main.atkPart[2]=100;
                    Main.atkPart[3]=100;
                    Main.atkPart[4]=100;
                    Main.atkPart[5]=10000;
                    Main.atkPart[6]=10000;
                    Main.settings.atkPart.Value=Main.atkPart;
                    tg.isOn = false;foreach(var del in refresh_list)del();
                };
                container2.Children.Add(taiwuToggle);
            }
            container.Children.Add(container2);
            container2 = new Container();
            container2.Element.PreferredSize.Add(0f);
            container2.Element.PreferredSize.Add(60f);
            container2.Group.Direction = 0;
            container2.Group.Spacing = 4f;
            {
                TaiwuInputField taiwuInputField = new TaiwuInputField();
                taiwuInputField.Name = "";
                taiwuInputField.Text = Main.aTF.ToString();
                TaiwuLabel lab3= new TaiwuLabel { Name = "Label", Text = "式增加系数" };
                taiwuInputField.OnEndEdit = delegate(string value, InputField inputField) {
                    Main.aTF=int.Parse(value);
                    Main.settings.aTF.Value=Main.aTF;
                };
                container2.Children.Add(lab3);
                container2.Children.Add(taiwuInputField);
            }
            container.Children.Add(container2);
            for(int i=0;i<19;i++){
                (new Sub(Main.atkTyp,i,Main.natkTyp[i])).Addto(container2);
                if ((i&3)==2){
                    container.Children.Add(container2);
                    container2 = new Container();
                    container2.Element.PreferredSize.Add(0f);
                    container2.Element.PreferredSize.Add(60f);
                    container2.Group.Direction = 0;
                    container2.Group.Spacing = 4f;
                }
            }
            Mod.SettingUI = container;
        }
    }
#endif
    [BepInPlugin("%%PLUGIN_ID%%", "%%NAMESPACE_ID%%", "0.1.5")]
    public class Main : BaseUnityPlugin {
        public static Action<string> logger=delegate(string s){};

        public static int[] atkPart=new int[]{100,100,100,100,100,100,100,7500};
        public static int[] atkTyp=new int[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
        public static int aTF=100;
        public static bool use_ui=true;
        public static readonly string[] natkPart={"胸背","腰腹","头颈","左臂","右臂","左腿","右腿","不变"};
        public static readonly string[] natkTyp={"掷","弹","御","劈","刺","撩","崩","点","拿","音","缠","咒","机","药","毒","无","扫","万","杀"};
        public static Settings settings = new Settings();
#if USE_UI
        public static UI ui=new UI();
#endif

        private void Awake()
        {
            // Harmony.DEBUG=true;
            var harmony=new Harmony("%%PLUGIN_ID%%");
#if DEBUG
            logger=delegate(string s){Logger.LogInfo("%%NAMESPACE_ID%%:"+s);};
            logger("开始注入");
#endif
            logger("即将进行自动变招的patch");
            harmony.PatchAll(Assembly.GetExecutingAssembly());
            logger("加载完成");
            UnityEngine.Object.DontDestroyOnLoad(this);
            settings.Init(base.Config);
            atkPart=settings.atkPart.Value;
            atkTyp=settings.atkTyp.Value;
            aTF=settings.aTF.Value;
            use_ui=settings.use_ui.Value;
#if USE_UI
            if(use_ui){
                ui.Init();
            }
#endif
        }

        [HarmonyPatch(typeof(BattleSystem), "ActionEventAttack")]
        public static class BattleSystemActionEventAttack {
            static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions){ // 通过ThirdItemId的读写修改进行注入
                logger("   ->搜索ldc.i4.0后面的GetChangeVaule");
                uint flag=0xDEADBEFF;
                int count=0;
                flag=0xDEADCAFE;
                //MethodInfo find=typeof(MakeSystem).GetMethod("GetChangeVaule",(BindingFlags)(-1)); // -1是BindingFlags.All的意思。
                foreach (var instruction in instructions) { // 理论上只有before和hit节需要处理
                    /*if(flag==0xDEADBEFF && instruction.opcode==OpCodes.Ldc_I4_0){ // before
                        yield return instruction;
                        flag=0xDEADCAFE;
                    } else */if(flag==0xDEADCAFE){
                        // logger("[II]:DEADCAFE at "+count+", current instruction: "+instruction.opcode.ToString());
                        // instruction.opcode==OpCodes.Callvirt && (MethodInfo)instruction.operand == typeof(what_you_want).GetMethod("to_call")
                        // instruction.opcode==OpCodes.Ldfld && ((FieldInfo)instruction.operand).Name == "name"
                        if(instruction.opcode==OpCodes.Stfld && ((FieldInfo)instruction.operand).Name == "actorChooseAttackPart"){ // hit
                            logger("[II]:找到this.actorChooseAttackPart = ...");
                            //yield return instruction; //int

                            var label = new CodeInstruction(OpCodes.Nop);
                            label.labels=instruction.labels;
                            instruction.labels=new List<System.Reflection.Emit.Label>();
                            yield return label;

                            yield return new CodeInstruction(OpCodes.Ldarg_0,null);
                            yield return new CodeInstruction(OpCodes.Ldfld,typeof(BattleSystem).GetField("attackPartChooseObbs",(BindingFlags)(-1)));
                            yield return new CodeInstruction(OpCodes.Ldarg_0,null);
                            yield return new CodeInstruction(OpCodes.Ldfld,typeof(BattleSystem).GetField("choosePartGetCost",(BindingFlags)(-1)));
                            // stack: [ ? this int[] ]
                            yield return new CodeInstruction(OpCodes.Call,typeof(BattleSystemActionEventAttack).GetMethod("WiseAuto"));
                            // instruction should return int(=0) for skipping further instructions
                            yield return instruction; // this instruction may contains a label
                            flag=0;
                        }else{ // miss
                            yield return instruction;
                            //flag=0xDEADBEFF;
                        }
                    } else { // after
                        yield return instruction;
                    }
                    count++;
                }
                if(flag!=0)logger("[EE]:注入失败，请检查源码是否发生了改变");
            }
            public static int WiseAuto(int res, int[] attackPartChooseObbs, int[] choosePartGetCost){
                int prob=atkPart[7];
                res=-1;
                for(int i=0;i<7;i++){
                    int tmp=attackPartChooseObbs[i]*atkPart[i]+(i==2?0:aTF*atkTyp[choosePartGetCost[i]]);
                    if(tmp>prob){
                        prob=tmp;
                        res=i;
                    }
                }
                return res;
            }
        }
    }
}

